<?php

use app\shop\enums\notify\NotifyMessageType;
use Phinx\Db\Adapter\MysqlAdapter;
use think\facade\Db;
use think\migration\Migrator;

class JoyshopVersion110 extends Migrator
{
    public int $time = 0;

    public function up(): void
    {
        $this->time = time();

        $this->shop_notify();
        $this->shop_notify_config();

        $this->insertNotifyConfigData();
        $this->updateUser();
        $this->updateSetting();
    }

    public function shop_notify(): void
    {
        if (!$this->hasTable('shop_notify')) {
            $table = $this->table('shop_notify', [
                'id'          => false,
                'comment'     => '消息通知表',
                'row_format'  => 'DYNAMIC',
                'primary_key' => 'id',
                'collation'   => 'utf8mb4_unicode_ci',
            ]);
            $table->addColumn('id', 'integer', ['comment' => 'ID', 'identity' => true, 'signed' => false, 'null' => false])
                ->addColumn('sender_id', 'integer', ['comment' => '发送人ID', 'signed' => false, 'null' => false, 'default' => '0'])
                ->addColumn('receiver_id', 'string', ['comment' => '接收人ID', 'limit' => 255, 'null' => false, 'default' => ''])
                ->addColumn('reader_id', 'string', ['comment' => '查看人ID', 'limit' => 255, 'null' => false, 'default' => ''])
                ->addColumn('message_type', 'string', ['comment' => '消息类型', 'limit' => 255, 'null' => false, 'default' => ''])
                ->addColumn('message', 'string', ['comment' => '消息内容', 'limit' => 255, 'null' => false, 'default' => ''])
                ->addColumn('message_data', 'json', ['comment' => '消息数据'])
                ->addColumn('create_time', 'biginteger', ['comment' => '添加时间', 'limit' => 20, 'signed' => false, 'null' => false, 'default' => '0'])
                ->addColumn('update_time', 'biginteger', ['comment' => '更新时间', 'limit' => 20, 'signed' => false, 'null' => false, 'default' => '0'])
                ->addIndex(['receiver_id', 'reader_id'], ['name' => 'idx_status', 'type' => 'BTREE'])
                ->addIndex(['create_time'], ['type' => 'BTREE'])
                ->create();
        }
    }

    public function shop_notify_config(): void
    {
        if (!$this->hasTable('shop_notify_config')) {
            $table = $this->table('shop_notify_config', [
                'id'          => false,
                'comment'     => '消息通知配置表',
                'row_format'  => 'DYNAMIC',
                'primary_key' => 'id',
                'collation'   => 'utf8mb4_unicode_ci',
            ]);
            $table->addColumn('id', 'integer', ['comment' => 'ID', 'identity' => true, 'signed' => false, 'null' => false])
                ->addColumn('message_type', 'string', ['comment' => '消息类别', 'limit' => 100, 'null' => false, 'default' => ''])
                ->addColumn('audio_path', 'string', ['comment' => '通知音频文件路径', 'limit' => 255, 'null' => false, 'default' => ''])
                ->addColumn('receiver_ids', 'string', ['comment' => '应用策略的管理员ID', 'limit' => 255, 'null' => false, 'default' => ''])
                ->addColumn('receiver_rule', 'integer', ['comment' => '消息策略:0=黑名单,1=白名单', 'limit' => MysqlAdapter::INT_TINY, 'null' => false, 'default' => '0'])
                ->addColumn('create_time', 'biginteger', ['comment' => '添加时间', 'limit' => 20, 'signed' => false, 'null' => false, 'default' => '0'])
                ->addColumn('update_time', 'biginteger', ['comment' => '更新时间', 'limit' => 20, 'signed' => false, 'null' => false, 'default' => '0'])
                ->addIndex(['message_type'], ['type' => 'BTREE'])
                ->addIndex(['receiver_ids'], ['type' => 'BTREE'])
                ->create();
        }
    }

    public function updateUser(): void
    {
        $user = $this->table('shop_user');

        if (!$user->hasColumn('unionid')) {
            $user->addColumn('unionid', 'string', ['limit' => 32, 'comment' => '微信unionid', 'null' => false, 'default' => ''])->save();
        }

        if (!$user->hasColumn('source')) {
            $user->addColumn('source', 'string', ['limit' => 32, 'comment' => '注册来源客户端 ', 'null' => false, 'default' => 'miniapp'])->save();
        }
    }

    public function insertNotifyConfigData(): void
    {
        $table = $this->table('shop_notify_config');

        $messageTypeMap = array_keys(NotifyMessageType::getAllDescriptions());
        $messageTypes   = Db::name('shop_notify_config')->column('message_type');
        $data           = array_map(function ($type) {
            return [
                'message_type' => $type,
                'create_time'  => $this->time,
                'update_time'  => $this->time
            ];
        }, array_diff($messageTypeMap, $messageTypes));

        if (!empty($data)) {
            $table->insert($data)->saveData();
        }
    }

    public function updateSetting(): void
    {
        $table = $this->table('shop_setting');

        $data = [
            // 基本配置
            [
                'name'    => 'h5_domain', 'group' => 'basic', 'title' => 'H5页面域名', 'tip' => '', 'type' => 'string',
                'value'   => '',
                'content' => '', 'rule' => 'required', 'extend' => '{"blockHelp": "H5端页面访问域名，以 / 结尾，如：http(s)://www.xxx.com/"}', 'weigh' => 0, 'allow_del' => 0
            ],
            // 支付宝配置
            [
                'name'    => 'alipay_app_id', 'group' => 'alipay', 'title' => '应用ID(APPID)', 'tip' => '支付宝分配给开发者的应用ID', 'type' => 'password',
                'value'   => '',
                'content' => '', 'rule' => 'required', 'extend' => '', 'weigh' => 0, 'allow_del' => 0
            ],
            [
                'name'    => 'alipay_app_secret_cert', 'group' => 'alipay', 'title' => '应用私钥', 'tip' => '输入应用私钥字符串', 'type' => 'textarea',
                'value'   => '',
                'content' => '', 'rule' => 'required', 'extend' => '{"blockHelp":"在 https://open.alipay.com/develop/manage 《应用详情-开发设置-接口加签方式》 中设置，加签方式选择证书"}', 'weigh' => 0, 'allow_del' => 0
            ],
            [
                'name'    => 'alipay_app_public_cert_path', 'group' => 'alipay', 'title' => '应用公钥证书', 'tip' => '应用私钥设置好之后可以下载得到', 'type' => 'password',
                'value'   => '',
                'content' => '', 'rule' => 'required', 'extend' => '{"blockHelp":"输入应用公钥证书（appCertPublicKey_xxx.crt）在服务器上的绝对路径（注意权限）"}', 'weigh' => 0, 'allow_del' => 0
            ],
            [
                'name'    => 'alipay_public_cert_path', 'group' => 'alipay', 'title' => '支付宝公钥证书', 'tip' => '应用私钥设置好之后可以下载得到', 'type' => 'password',
                'value'   => '',
                'content' => '', 'rule' => 'required', 'extend' => '{"blockHelp":"输入支付宝公钥证书（alipayCertPublicKey_RSA2.crt）在服务器上的绝对路径（注意权限）"}', 'weigh' => 0, 'allow_del' => 0
            ],
            [
                'name'    => 'alipay_root_cert_path', 'group' => 'alipay', 'title' => '支付宝根证书', 'tip' => '应用私钥设置好之后可以下载得到', 'type' => 'password',
                'value'   => '',
                'content' => '', 'rule' => 'required', 'extend' => '{"blockHelp":"输入支付宝根证书（alipayRootCert.crt）在服务器上的绝对路径（注意权限）"}', 'weigh' => 0, 'allow_del' => 0
            ],
        ];

        $existData = Db::name($table->getName())->select()->toArray();
        foreach ($data as $key => $item) {
            if (in_array($item['name'], array_column($existData, 'name'))) {
                unset($data[$key]);
            }
            if ($item['name'] == $item['group'] && in_array($item['group'], array_column($existData, 'group'))) {
                unset($data[$key]);
            }
        }

        Db::startTrans();
        try {
            // 更新支付配置项
            Db::name($table->getName())->where([
                ['group', '=', 'pay_group'],
                ['type', '=', 'array']
            ])->update([
                'name'  => 'pay_group',
                'value' => json_encode([
                    ['key' => 'wxpay', 'value' => '微信支付'],
                    ['key' => 'alipay', 'value' => '支付宝支付'],
                ], JSON_UNESCAPED_UNICODE)
            ]);

            if ($data) {
                $table->insert($data)->saveData();
            }

            Db::commit();
        } catch (\Throwable $e) {
            Db::rollback();
            throw $e;
        }
    }
}
